﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WSServer;
using BartonExtension;


using Microsoft.AspNet.SignalR.Client;

using Model.App;
using Services.Common;
using Services.Weixin;

namespace Services.PushNotification
{
    public class PushOperation : IDisposable
    {
        public string operationId { get; set; }
        public Task task { get; set; }
        public Action<PushOperation> onTaskEnd { get; set; }
        public bool isEnd { get; set; }

        public void Dispose()
        {
            this.Dispose(true);////释放托管资源
            GC.SuppressFinalize(this);//请求系统不要调用指定对象的终结器. //该方法在对象头中设置一个位，系统在调用终结器时将检查这个位
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)//_isDisposed为false表示没有进行手动dispose
            {
                if (disposing)
                {
                    //清理托管资源
                    task.Dispose();
                }
                //清理非托管资源
            }
            _isDisposed = true;
        }

        private bool _isDisposed;
        public void Init()
        {
            var _this = this;
            task.ContinueWith((tobj) =>
                {
                    if(_this.onTaskEnd != null)
                    {
                        _this.onTaskEnd(_this);
                    }
                });
        }
        public void Go()
        {
            if(task.Status != TaskStatus.Running)
            {
                task.Start();
            }
        }
        public static PushOperation NewWithTask(Task t,Action<PushOperation> onTaskEnd,bool isStartNow)
        {
            PushOperation op = new PushOperation()
            {
                operationId = IDGenerator.GenerateID().ToString(),
                task = t,
                isEnd = false,
                onTaskEnd = onTaskEnd
            };
            op.Init();
            if(isStartNow)
            {
                op.task.Start();
            }
            return op;
        }
    }
    public class Pusher
    {
        const int MAX_CONCURRENCE_OPS = 5;
        private static ConcurrentQueue<ISMPushContent> pushQueue { get; set; }
        private static List<PushOperation> operations { get; set; }
        private static HubConnection hubConnection { get; set; }
        private static IHubProxy hubProxy { get; set; }

        private static object locker = new object();
        public static string SERVER_ID { get; set; }
        public static void Init()
        {
            pushQueue = new ConcurrentQueue<ISMPushContent>();
            operations = new List<PushOperation>();
            SERVER_ID = Guid.NewGuid().ToString();
            initHub();
        }
        public static void initHub()
        {
            hubConnection = new HubConnection("http://localhost:8000");

            hubProxy = hubConnection.CreateHubProxy("oPNotificationHub");
            hubProxy.On("userOffline", async(data)=>
            {
                string openid = data[0].state.Split(',')[0];
                string username = data[0].state.Split(',')[1];
                ISMWeixinPushRequest request = new ISMWeixinPushRequest()
                {
                    from = username,
                    openid = openid,
                    pushcontent = data[1].context
                };
                ISMServiceModel model = new ISMServiceModel()
                {
                    operationIdentifier = ISMWeixinServiceProvider.WEIXIN_PUSH,
                    userinfo = request
                };
                var provider = ISMServiceStack.sharedInstance[ISMServiceStackKeys.WEIXIN];
                var result = await provider.doProcess(model);
                if(result.isOperationSuccess)
                {
                    
                }
            });
            hubConnection.Start().Wait();
        }

        public static void Push(ISMPushContent content)
        {
            pushQueue.Enqueue(content);
            Start();
        }
        private static void Start()
        {
            lock (locker)
            {
                if (operations.Count >= 0 && operations.Count < MAX_CONCURRENCE_OPS)
                {
                    PushOperation op = PushOperation.NewWithTask(new Task(() =>
                        {
                            //DequeueItem
                            ISMPushContent pushContent;
                            while (!pushQueue.TryDequeue(out pushContent) && pushQueue.Count > 0){
                                System.Threading.Thread.Sleep(200);
                            }
                            if(pushContent != null)
                            {
                                if (hubConnection.State != ConnectionState.Connected)
                                {
                                    hubConnection.Start().Wait();
                                }
                                hubProxy.Invoke("Push", pushContent.ToJson().encode(), pushContent.fromId, pushContent.receiverId, 0).Wait();
                            }
                        }), (_op) =>
                        {
                            int index = operations.FindIndex(o =>
                            {
                                return o.operationId == _op.operationId;
                            });
                            if(index != -1)
                            {
                                operations.RemoveAt(index);
                            }
                        }, false);
                    operations.Add(op);
                    op.Go();
                }
            }
        }
        
    }
}
